package org.shalicon.chip
package pipeline

import utils.Parameter

import chisel3._
import chisel3.util.{Decoupled, MuxLookup, Valid, log2Floor}


// simple basic branch predictor

class BasicPredictorBundle(implicit p: Parameter) extends ShBundle()(p) {
  val takens = Bool()
  val uid = UInt(log2Floor(p.fetch_count).W)
}

class BrFeedback(implicit p: Parameter) extends ShBundle()(p) {
  val vaddr = UInt(VADDR_WIDTH) // // when using 2-bit bp, this is unnecessary
  val ataken = Bool()
  val uid = UInt(log2Floor(p.fetch_count).W)
}
class BasicPredictor(implicit p: Parameter) extends ShModule()(p) {
  val io = IO(new ShBundle()(p) {
    val cur_pc = Input(UInt(VADDR_WIDTH)) // when using 2-bit bp, this is unnecessary
    val resp = Decoupled(Vec(p.fetch_count, new BasicPredictorBundle()))
    // update the branch predictor from the execution stage once we get true results
    val feedback = Flipped(Valid(new BrFeedback()))
  })

  val state = RegInit(Vec(p.fetch_count, 3.U(2.W)))

  for (i <- 0 until p.fetch_count) {
    state(i) := Mux(io.feedback.valid && (io.feedback.bits.uid === i.U), Mux(io.feedback.bits.ataken, MuxLookup(state(i), state(i))(Seq(
      0.U -> 0.U,
      1.U -> 0.U,
      2.U -> 1.U,
      3.U -> 2.U
    )), MuxLookup(state(i), state(i))(Seq(
      0.U -> 1.U,
      1.U -> 2.U,
      2.U -> 3.U,
      3.U -> 3.U
    ))), state(i))
  }

  // pre-decode to determine whether it is a branch inst
  val opcode = "b1100011".U
  for (i <- 0 to p.fetch_count) {
    io.resp.bits(i).uid := i.U
    io.resp.bits(i).takens := MuxLookup(state(i), false.B)(Seq(
      0.U -> true.B,
      1.U -> true.B,
      2.U -> false.B,
      3.U -> false.B
    ))
  }


}

class GsharePredictor(history_size: Int)(implicit p: Parameter) extends ShModule {
  val io = IO(new ShBundle()(p) {

  })
}